package admin.server.service.impl;

import admin.dao.mapper.*;
import admin.dao.model.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import admin.common.vo.PageVo;
import admin.server.dao.UmsRoleDao;
import admin.server.model.dto.UmsMenuNodeDto;
import admin.server.model.dto.UmsResourceDto;
import admin.server.model.dto.UmsRoleDetailDto;
import admin.server.model.dto.UmsRoleDto;
import admin.server.model.param.UmsRoleCreateParam;
import admin.server.model.param.UmsRoleUpdateParam;
import admin.server.service.UmsMenuService;
import admin.server.service.UmsResourceService;
import admin.server.service.UmsRoleService;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 后台角色管理Service实现类
 * Created by zgb on 2018/9/30.
 */
@Service
public class UmsRoleServiceImpl implements UmsRoleService {
    @Autowired
    private UmsRoleMapper roleMapper;
    @Autowired
    private UmsRoleMenuRelationMapper roleMenuRelationMapper;


    @Autowired
    private UmsRoleDao roleDao;
    @Autowired
    private UmsResourceService resourceService;
    @Autowired
    private UmsRoleResourceRelationMapper roleResourceRelationMapper;

    @Autowired
    private UmsAdminRoleRelationMapper adminRoleRelationMapper;


    @Autowired
    private UmsResourceMapper resourceMapper;
    @Autowired
    private UmsMenuMapper menuMapper;


    @Autowired
    private UmsMenuService menuService;


    public void uniqueCheck(UmsRole record) throws Exception {
        if (org.apache.commons.lang3.StringUtils.isBlank(record.getName())) {
            throw new Exception("名称 必填！");
        }
        //更新，不变
        if (record.getId() != null) {
            UmsRole one = roleMapper.selectByPrimaryKey(record.getId());
            if (Objects.equals(one.getName(), record.getName())) {
                return;
            }
        }
        UmsRoleExample umsRoleExample = new UmsRoleExample();
        umsRoleExample.createCriteria().andNameEqualTo(record.getName());
        List<UmsRole> list = roleMapper.selectByExample(umsRoleExample);
        if (!list.isEmpty()) {
            throw new Exception("名称 已存在 请勿重复添加！");
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(UmsRoleCreateParam roleCreateParam) throws Exception {
        uniqueCheck(BeanUtil.toBean(roleCreateParam, UmsRole.class));
        UmsRole role = BeanUtil.toBean(roleCreateParam, UmsRole.class);
        role.setFeiShuCodeRegisteNecessaryYn(false);
        role.setCreateTime(new Date());
        roleMapper.insertSelective(role);
        Set<Long> menuIds = new HashSet<>();
        menuIds.addAll(roleCreateParam.getMenuIds());
        //绑定必要菜单
        UmsMenuExample umsMenuExample = new UmsMenuExample();
        if (!BooleanUtil.isTrue(roleCreateParam.getSupAdminYn())) {
            umsMenuExample.createCriteria().andNecessaryYnEqualTo(true);
        }
        List<UmsMenu> umsMenus = menuMapper.selectByExample(umsMenuExample);
        menuIds.addAll(umsMenus.stream().map(e -> e.getId()).collect(Collectors.toList()));
        this.allocMenu(role.getId(), new ArrayList<>(menuIds));
        Set<Long> resourceIds = new HashSet<>();
        resourceIds.addAll(roleCreateParam.getResourceIds());
        //绑定必要资源
        UmsResourceExample umsResourceExample = new UmsResourceExample();
        if (!BooleanUtil.isTrue(roleCreateParam.getSupAdminYn())) {
            umsResourceExample.createCriteria().andNecessaryYnEqualTo(true);
        }
        List<UmsResource> umsResources = resourceMapper.selectByExample(umsResourceExample);
        resourceIds.addAll(umsResources.stream().map(e -> e.getId()).collect(Collectors.toList()));
        this.allocResource(role.getId(), new ArrayList<>(resourceIds));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(UmsRoleUpdateParam roleUpdateParam) throws Exception {
        uniqueCheck(BeanUtil.toBean(roleUpdateParam, UmsRole.class));
        Set<Long> menuIds = new HashSet<>();
        menuIds.addAll(roleUpdateParam.getMenuIds());
        //绑定必要菜单
        UmsMenuExample umsMenuExample = new UmsMenuExample();
        if (!BooleanUtil.isTrue(roleUpdateParam.getSupAdminYn())) {
            umsMenuExample.createCriteria().andNecessaryYnEqualTo(true);
        }
        List<UmsMenu> umsMenus = menuMapper.selectByExample(umsMenuExample);
        menuIds.addAll(umsMenus.stream().map(e -> e.getId()).collect(Collectors.toList()));
        this.allocMenu(roleUpdateParam.getId(), new ArrayList<>(menuIds));
        Set<Long> resourceIds = new HashSet<>();
        resourceIds.addAll(roleUpdateParam.getResourceIds());
        //绑定必要资源
        UmsResourceExample umsResourceExample = new UmsResourceExample();
        if (!BooleanUtil.isTrue(roleUpdateParam.getSupAdminYn())) {
            umsResourceExample.createCriteria().andNecessaryYnEqualTo(true);
        }
        List<UmsResource> umsResources = resourceMapper.selectByExample(umsResourceExample);
        resourceIds.addAll(umsResources.stream().map(e -> e.getId()).collect(Collectors.toList()));
        this.allocResource(roleUpdateParam.getId(), new ArrayList<>(resourceIds));

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int delete(List<Long> ids) {
        UmsRoleExample example = new UmsRoleExample();
        example.createCriteria().andIdIn(ids);
        int count = roleMapper.deleteByExample(example);
        UmsAdminRoleRelationExample adminRoleRelationExample = new UmsAdminRoleRelationExample();
        adminRoleRelationExample.createCriteria().andRoleIdIn(ids);
        adminRoleRelationMapper.deleteByExample(adminRoleRelationExample);
        UmsRoleMenuRelationExample umsRoleMenuRelationExample = new UmsRoleMenuRelationExample();
        umsRoleMenuRelationExample.createCriteria().andRoleIdIn(ids);
        roleMenuRelationMapper.deleteByExample(umsRoleMenuRelationExample);
        UmsRoleResourceRelationExample umsRoleResourceRelationExample = new UmsRoleResourceRelationExample();
        umsRoleResourceRelationExample.createCriteria().andRoleIdIn(ids);
        roleResourceRelationMapper.deleteByExample(umsRoleResourceRelationExample);
        resourceService.initResourceRolesMap();
        return count;
    }

    @Override
    public List<UmsRole> list() {
        UmsRoleExample umsRoleExample = new UmsRoleExample();
        umsRoleExample.createCriteria().andStatusEqualTo(true);
        return roleMapper.selectByExample(umsRoleExample);
    }

    @Override
    public PageVo<UmsRoleDto> list(String keyword, Integer pageSize, Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        UmsRoleExample example = new UmsRoleExample();
        if (!StringUtils.isEmpty(keyword)) {
            example.createCriteria().andNameLike("%" + keyword + "%");
        }
        List<UmsRole> umsRoles = roleMapper.selectByExample(example);
        List<UmsRoleDto> umsRoleDtos = BeanUtil.copyToList(umsRoles, UmsRoleDto.class);
        for (UmsRoleDto item : umsRoleDtos) {
            UmsAdminRoleRelationExample umsAdminRoleRelationExample = new UmsAdminRoleRelationExample();
            umsAdminRoleRelationExample.createCriteria().andRoleIdEqualTo(item.getId());
            long l = adminRoleRelationMapper.countByExample(umsAdminRoleRelationExample);
            item.setAdminCount(Integer.valueOf(Long.toString(l)));
        }

        return PageVo.restPage(umsRoles, umsRoleDtos);
    }

    private void check(List<UmsMenuNodeDto> tree, UmsRoleDetailDto umsRoleDetailDto) {
        for (UmsMenuNodeDto umsMenuNodeDto : tree) {
            if (umsRoleDetailDto.getMenuIds().contains(umsMenuNodeDto.getId())) {
                umsMenuNodeDto.setCheck(true);
            }
            for (UmsResourceDto umsResourceDto : umsMenuNodeDto.getResourceList()) {
                if (umsRoleDetailDto.getResourceIds().contains(umsResourceDto.getId())) {
                    umsResourceDto.setCheck(true);
                }
            }
            this.check(umsMenuNodeDto.getChildren(), umsRoleDetailDto);
        }
    }

    @Override
    public UmsRoleDetailDto detail(Long id) {
        UmsRole umsRole = roleMapper.selectByPrimaryKey(id);
        UmsRoleDetailDto umsRoleDetailDto = BeanUtil.toBean(umsRole, UmsRoleDetailDto.class);
        UmsRoleMenuRelationExample umsRoleMenuRelationExample = new UmsRoleMenuRelationExample();
        umsRoleMenuRelationExample.createCriteria().andRoleIdEqualTo(umsRole.getId());
        List<UmsRoleMenuRelation> umsRoleMenuRelations = roleMenuRelationMapper.selectByExample(umsRoleMenuRelationExample);
        umsRoleDetailDto.setMenuIds(umsRoleMenuRelations.stream().map(e -> e.getMenuId()).collect(Collectors.toList()));
        UmsRoleResourceRelationExample umsRoleResourceRelationExample = new UmsRoleResourceRelationExample();
        umsRoleResourceRelationExample.createCriteria().andRoleIdEqualTo(umsRole.getId());
        List<UmsRoleResourceRelation> umsRoleResourceRelations = roleResourceRelationMapper.selectByExample(umsRoleResourceRelationExample);
        umsRoleDetailDto.setResourceIds(umsRoleResourceRelations.stream().map(e -> e.getResourceId()).collect(Collectors.toList()));
        List<UmsMenuNodeDto> tree = menuService.treeList(true);
        this.check(tree, umsRoleDetailDto);
        umsRoleDetailDto.setTree(tree);
        return umsRoleDetailDto;
    }


    @Override
    public List<UmsMenu> getMenuList(Long adminId) {
        return roleDao.getMenuList(adminId);
    }

    @Override
    public List<UmsMenu> listMenu(Long roleId) {
        return roleDao.getMenuListByRoleId(roleId);
    }

    @Override
    public List<UmsResource> listResource(Long roleId) {
        return roleDao.getResourceListByRoleId(roleId);
    }


    private int allocMenu(Long roleId, List<Long> menuIds) {
        //先删除原有关系
        UmsRoleMenuRelationExample example = new UmsRoleMenuRelationExample();
        example.createCriteria().andRoleIdEqualTo(roleId);
        roleMenuRelationMapper.deleteByExample(example);
        //批量插入新关系
        for (Long menuId : menuIds) {
            UmsRoleMenuRelation relation = new UmsRoleMenuRelation();
            relation.setRoleId(roleId);
            relation.setMenuId(menuId);
            roleMenuRelationMapper.insert(relation);
        }
        return menuIds.size();
    }


    private int allocResource(Long roleId, List<Long> resourceIds) {
        //先删除原有关系
        UmsRoleResourceRelationExample example = new UmsRoleResourceRelationExample();
        example.createCriteria().andRoleIdEqualTo(roleId);
        roleResourceRelationMapper.deleteByExample(example);
        //批量插入新关系
        for (Long resourceId : resourceIds) {
            UmsRoleResourceRelation relation = new UmsRoleResourceRelation();
            relation.setRoleId(roleId);
            relation.setResourceId(resourceId);
            roleResourceRelationMapper.insert(relation);
        }
        resourceService.initResourceRolesMap();
        return resourceIds.size();
    }

}
